#ifndef __C_DELEGATE_H_INCLUDED__
#define __C_DELEGATE_H_INCLUDED__
#include "list"


template<class TRet TEMPLATE_PARAMS>
class C_DELEGATE
{
public:
	void* Data;

    typedef I_DELEGATE<TRet TEMPLATE_ARGS> IDelegate;
    typedef std::list<IDelegate*> DelegateList;

    C_DELEGATE(IDelegate* pDelegate = NULL) : Data(0) 
	{ 
		Add(pDelegate); 
	}

    ~C_DELEGATE() { RemoveAll(); }
    
	bool IsNull() { return (m_DelegateList.empty()); }

    C_DELEGATE<TRet TEMPLATE_ARGS>& operator=(IDelegate* pDelegate)
    {
        RemoveAll();
        Add(pDelegate);
        return *this;
    }

    C_DELEGATE<TRet TEMPLATE_ARGS>& operator+=(IDelegate* pDelegate)
    {
        Add(pDelegate);
        return *this;
    }

    C_DELEGATE<TRet TEMPLATE_ARGS>& operator-=(IDelegate* pDelegate)
    {
        Remove(pDelegate);
        return *this;
    }

    TRet operator()(PARAMS)
    {
        return Invoke(ARGS);
    }

private:
    void Add(IDelegate* pDelegate)
    {
        if(pDelegate != NULL)
            m_DelegateList.push_back(pDelegate);
    }

    void Remove(IDelegate* pDelegate)
    {
        typename DelegateList::iterator it;
        for(it = m_DelegateList.begin(); it != m_DelegateList.end(); ++it)
        {
            if((*it)->Compare(pDelegate))
            {
                delete (*it);
                m_DelegateList.erase(it);
                break;
            }
        }
    }

    void RemoveAll()
    {
        typename DelegateList::iterator it;
        for(it = m_DelegateList.begin(); it != m_DelegateList.end(); ++it)
            delete (*it);

        m_DelegateList.clear();
    }

    TRet Invoke(PARAMS)
    {
        typename DelegateList::const_iterator it;
        
        for(it = m_DelegateList.begin(); it != --m_DelegateList.end(); ++it)
            (*it)->Invoke(ARGS);

        return m_DelegateList.back()->Invoke(ARGS);
    }

private:
    DelegateList m_DelegateList;
};
#endif